%{
/* vim: set list et sts=2 sw=2:  */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

static int indent = 0,
           ts = 4,
           sp_indent = 0,
           next_indent = 0;

void put_spaces(int);

%}

%s COMMENT ESC STRLITERAL PREPROC CPPCOMMENT

NL      ("\n"|"\r\n")

%%

 /* different mindset:
  * view input stream as a continuous flow of characters (in other words, do not
  * separate text by lines) */

<INITIAL>^[ \t]*#[ \t]*[a-zA-Z_]+ {
                             int i;
                             i = 1;
                             while (yytext[i] && !isalpha(yytext[i]))
                               i++;
                             printf("#%s", yytext + i);
                             BEGIN PREPROC;
                           }
<PREPROC>"\\"{NL} { ECHO; }
<PREPROC>"\t"     { put_spaces(ts); }
<PREPROC>[ \t]+$  { /* eat trailing whitespace */ }
<PREPROC>{NL}     { ECHO; BEGIN 0; }
<PREPROC>.        { ECHO; }


<INITIAL>"\""                   { ECHO; BEGIN STRLITERAL; }
<STRLITERAL>"\\"(.|[ \t\v\r\n]) { ECHO; }
<STRLITERAL>"\""                { ECHO; BEGIN 0; }
<STRLITERAL>.|[ \t\v\r\n]*      { ECHO; }

<INITIAL>[ \t\v\r\n]*"{"[ \t\v\r\n]* {
                                       puts("");
                                       put_spaces(indent++ * ts);
                                       puts("{");
                                       next_indent = 1;
                                       /*
                                       int i = 0;
                                       while (yytext[i]) {
                                         if (yytext[i] == '{') {
                                           put_spaces(indent++ * ts);
                                           puts("{");
                                         } else if (yytext[i] == '\r') {
                                           fputc('\r', stdout);
                                         } else if (yytext[i] == '\n') {
                                         } else if (yytext[i] == ' ' ) {
                                         } else if (yytext[i] == '\t' || yytext[i] == '\v') {
                                         } else {
                                         }
                                       }
                                       */
                                     }
<INITIAL>[ \t\v\r\n]*"}"             {
                                       puts("");
                                       put_spaces(--indent * ts);
                                       putchar('}');
                                     }

<INITIAL>^[ \t]*{NL} { puts(""); }
<INITIAL>^[ \t\v]* {
                     int i = 0;
                     if (next_indent) {
                       fputs("would have indented\n", stderr);
                       next_indent = 0;
                     }
                     put_spaces(indent * ts);
                   }

 /* <INITIAL>^[ \t]+"/*" | */
<INITIAL>"/*"        {
                       if (next_indent)
                         put_spaces(indent * ts);
                       fputs("/*", stdout);
                       BEGIN COMMENT;
                     }
<COMMENT>{NL}[ \t]*"*/" {
                          int i = 0;
                          while (yytext[i]) {
                            if (yytext[i] == '\t')
                              put_spaces(ts);
                            else
                              putchar(yytext[i]);
                            i++;
                          }

                          BEGIN 0;
                        }
<COMMENT>"*/"      { ECHO; BEGIN 0; }
<COMMENT>[ \t]+$   { /* kill trailing whitespace */ }
<COMMENT>{NL}[ \t]+[^\*]    {
                              int i = 1;

                              //fprintf(stderr, "r%d: matched: <%s>\n", __LINE__, yytext);

                              while (yytext[i] && isspace(yytext[i]))
                                i++;

                              puts("");
                              if (yytext[i] == '\0') {
                                put_spaces(ts * indent + 1);
                              } else {
                                put_spaces(ts * indent + 3);
                                putchar(yytext[i]);
                              }
                            }
<COMMENT>\t        { put_spaces(ts); }
<COMMENT>[a-z]+    { ECHO; }
<COMMENT>.         { ECHO; }

<INITIAL>"//" { ECHO; BEGIN CPPCOMMENT; }
<CPPCOMMENT>.*"\\"$ { ECHO; }
<CPPCOMMENT>.*$     { ECHO; BEGIN 0; }

<INITIAL>.  {
              if (next_indent) {
                fputs("next_indent\n", stderr);
                put_spaces(indent * ts);
                next_indent = 0;
              }
              ECHO;
            }

%%

int yywrap(void) {
  return 1;
}

int main(int argc, char **argv) {
  if (argc == 2)
    ts = atoi(argv[1]);
  yylex();
  return 0;
}

void put_spaces(int n) {
  int i;

  for (i = 0; i < n; i++) {
    putchar(' ');
  }
}
